package com.samehope.ar.socket.handler;

import com.alibaba.fastjson.JSON;
import com.samehope.ar.socket.strategy.CommandContext;
import com.samehope.ar.socket.support.MessageBody;
import com.samehope.ar.socket.support.NettyContext;
import com.samehope.ar.util.JwtTokenUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;


/**
 * @Description: App端的处理
 * @Author: ZhangLuo
 * @Email: 1946430@qq.com
 */
@Slf4j
public class AppClientHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    // 用于记录所有和服务端连接的channel
    public static ChannelGroup users = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    private JwtTokenUtil jwtTokenUtil;

    public AppClientHandler(JwtTokenUtil jwtTokenUtil) {
        this.jwtTokenUtil = jwtTokenUtil;
    }

    /**
     * 从管道读取消息
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {

        // 客户端传过来的信息
        String text = msg.text();
        // 声明消息体 并解析客户端消息 必须符合JSON结构的消息才允许接收
        MessageBody messageBody = null;
        try {
            messageBody = JSON.parseObject(text, MessageBody.class);
        } catch (Exception e) {
            NettyContext.writeMsgAndClose(ctx.channel(), "错误的消息格式, 连接被断开");
            e.printStackTrace();
            return;
        }

        CommandContext.handleCommand(messageBody, ctx.channel());
    }

    /**
     * 检查token是否有效, 且在有效期内
     * @param ctx
     * @return
     */
    private boolean checkToken(ChannelHandlerContext ctx) {
        String token = ctx.attr(HttpRequestHandler.TOKEN).get();
        if (jwtTokenUtil.isTokenExpired(token)) {
            NettyContext.writeMsgAndClose(ctx.channel(), "[TOKEN已过期, 请重新登录]");
            log.info("用户token过期, 被断开连接: {}", NettyContext.getMobile(ctx.channel()));
            return false;
        }
        return true;
    }

    /**
     * 在HttpRequestHandler
     * 之前被执行, 所以用户通道关系无法在这里加入
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        users.add(ctx.channel());
    }

    /**
     * 通道被关闭执行, 移除通道, 移除关联关系
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        users.remove(ctx.channel());
        NettyContext.remove(ctx.channel());
    }

    /**
     * 连接发生异常
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.warn("连接发生异常: {}", cause.getMessage(), cause);
        // 发生异常, 关闭连接
        Channel channel = ctx.channel();
        channel.close();
        users.remove(channel);
        NettyContext.remove(channel);
    }

}
